package mspbots.data.tl.prod.quickbooks.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.log4j.Log4j2;
import mspbots.data.tl.base.AbstractBaseServiceImpl;
import mspbots.data.tl.entity.ResultEntity;
import mspbots.data.tl.prod.quickbooks.mapper.OnlineProfitAndLossStandardMapper;
import mspbots.data.tl.prod.quickbooks.model.OnlineProfitAndLossStandard;
import mspbots.data.tl.prod.quickbooks.service.OnlineProfitAndLossStandardService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Jay.Yang
 */

@Service
@Log4j2
@DS("master")
public class OnlineProfitAndLossStandardServiceImpl extends AbstractBaseServiceImpl<OnlineProfitAndLossStandardMapper,
        OnlineProfitAndLossStandard> implements OnlineProfitAndLossStandardService {

    @Override
    public void sync(ResultEntity resultEntity) {
        JsonNode entity = resultEntity.getEntity();
        JsonNode header = entity.get("Header");
        if (ObjectUtils.isEmpty(header)){
            return;
        }
        OnlineProfitAndLossStandard data = OnlineProfitAndLossStandard.builder()
                .timePeriod(super.getStringValue(entity.get("timePeriod")))
                .time(super.getDateTimeValue(header.get("Time")))
                .currency(super.getStringValue(header.get("Currency")))
                .startPeriod(super.getDateValue(header.get("StartPeriod")))
                .endPeriod(super.getDateValue(header.get("EndPeriod")))
                .reportName(super.getStringValue(header.get("ReportName")))
                .reportBasis(super.getStringValue(header.get("ReportBasis")))
                .syncTime(resultEntity.getSyncDate())
                .build();
        data.setTenantCode(resultEntity.getTenantId());
        setHeaderOption(data, header.get("Option"));

        List<OnlineProfitAndLossStandard> dataList = new ArrayList<>();
        setRows(dataList, data, entity.get("Rows"));
        dataList.forEach(data1 -> {
            data1.setKey(data1.getTenantCode() + data1.getTimePeriod() + data1.getGroupName() +
                    (ObjectUtils.isEmpty(data1.getAccountId()) ? "" : data1.getAccountId()));
            OnlineProfitAndLossStandard dbData = super.baseMapper.selectOne(Wrappers.<OnlineProfitAndLossStandard>lambdaQuery()
                    .eq(OnlineProfitAndLossStandard::getKey, data1.getKey())
                    .last("limit 1"));

            if (ObjectUtils.isEmpty(dbData)) {
                super.baseMapper.insert(data1);
            } else {
                data1.setId(dbData.getId());
                super.baseMapper.updateById(data1);
            }
        });
    }

    private void setHeaderOption(OnlineProfitAndLossStandard data, JsonNode option) {
        if (ObjectUtils.isEmpty(option)) {
            return;
        }
        Iterator<JsonNode> optionIterator = option.elements();
        while (optionIterator.hasNext()) {
            JsonNode next = optionIterator.next();
            String name = super.getStringValue(next.get("Name"));
            if ("AccountingStandard".equalsIgnoreCase(name)) {
                data.setAccountingStandard(super.getStringValue(next.get("Value")));
            } else if ("NoReportData".equalsIgnoreCase(name)) {
                data.setNoReportData(super.getBooleanValue(next.get("Value")));
            }
        }
    }

    private void setRows(List<OnlineProfitAndLossStandard> dataList, OnlineProfitAndLossStandard data, JsonNode rows) {
        if (ObjectUtils.isEmpty(rows) || ObjectUtils.isEmpty(rows.get("Row"))) {
            return;
        }
        Iterator<JsonNode> rowIterator = rows.get("Row").elements();
        while (rowIterator.hasNext()) {
            JsonNode row = rowIterator.next();
            this.rowLevel(dataList, data, row);
        }
    }

    private void rowLevel(List<OnlineProfitAndLossStandard> dataList, OnlineProfitAndLossStandard data, JsonNode row) {
        OnlineProfitAndLossStandard baseData = OnlineProfitAndLossStandard.builder().build();
        BeanUtils.copyProperties(data, baseData);
        String type = super.getStringValue(row.get("type"));
        baseData.setType(type);
        baseData.setParentAccountId(baseData.getAccountId());
        baseData.setParentAccountName(baseData.getAccountName());
        if (!ObjectUtils.isEmpty(row.get("group"))) {
            baseData.setGroupName(row.get("group").asText());
        }
        if (!ObjectUtils.isEmpty(row.get("Header"))) {
            this.setColData(baseData, row.get("Header").get("ColData"));
        }
        if ("Data".equalsIgnoreCase(type)) {
            this.setColData(baseData, row.get("ColData"));
        } else if ("Section".equalsIgnoreCase(type)) {
            if (!ObjectUtils.isEmpty(row.get("Rows"))) {
                OnlineProfitAndLossStandard rowData = OnlineProfitAndLossStandard.builder().build();
                BeanUtils.copyProperties(baseData, rowData);
                this.setRows(dataList, rowData, row.get("Rows"));
            }
            this.setSummary(baseData, row.get("Summary"));
        }
        dataList.add(baseData);
    }

    private void setSummary(OnlineProfitAndLossStandard base, JsonNode summary) {
        if (ObjectUtils.isEmpty(summary) || ObjectUtils.isEmpty(summary.get("ColData"))) {
            return;
        }
        Iterator<JsonNode> colDataIterator = summary.get("ColData").elements();
        int i = 0;
        while (colDataIterator.hasNext()) {
            JsonNode colData = colDataIterator.next();
            if (i == 0) {
                base.setName(super.getStringValue(colData.get("value")));
            } else if (i == 1) {
                base.setTotal(super.getDoubleValue(colData.get("value")));
            }
            i++;
        }
    }

    private void setColData(OnlineProfitAndLossStandard base, JsonNode colData) {
        if (ObjectUtils.isEmpty(colData)) {
            return;
        }
        Iterator<JsonNode> colDataIterator = colData.elements();
        int i = 0;
        while (colDataIterator.hasNext()) {
            JsonNode data = colDataIterator.next();
            if (i == 0 && !ObjectUtils.isEmpty(data.get("id"))) {
                base.setAccountId(super.getIntegerValue(data.get("id")));
                base.setAccountName(super.getStringValue(data.get("value")));
            } else if (i == 1) {
                base.setTotal(super.getDoubleValue(data.get("value")));
            }
            i++;
        }
    }

}
